package com.elitel.frame.business.controller;

import com.elitel.common.elasticSearch.ESClient;
import com.elitel.common.elasticSearch.ESPageResponse;
import com.elitel.common.elasticSearch.ESPoolUtil;
import com.elitel.frame.base.component.RedisCacheComponent;
import com.elitel.frame.base.component.RedisCacheDataBase;
import com.elitel.frame.base.component.exportprojectdata.ElasticSerachInfo;
import com.elitel.frame.base.service.SysDocumentService;
import com.elitel.frame.main.entity.CfgExtsearch;
import com.elitel.frame.main.entity.SysDocument;
import com.elitel.frame.main.entity.SysPrjservice;
import com.elitel.frame.main.entity.vo.FullTextSearchVo;
import com.elitel.frame.main.entity.vo.JsonDataResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import opennlp.tools.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.client.transport.TransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;


/**
 * 全文检索服务
 * created by guoyanfei on 2018/3/28
 */
@Controller
@RequestMapping("/business/searchServer")
@Api(value = "/business/searchServer", tags = "全文检索服务接口")
public class SearchServerController {
    private static final Logger logger = LoggerFactory.getLogger(SearchServerController.class);
    @Autowired
    private RedisCacheComponent redisCacheComponent;
    @Autowired
    private RedisCacheDataBase redisCacheDataBase;
    @Autowired
    public ElasticSerachInfo elasticSerachInfo;
    @Autowired
    private SysDocumentService sysDocumentService;
    @Autowired(required = false)
    private RedisTemplate redisTemplate;
    //redis热词key前缀
    private String hotkey = "HOTWORD_";

    private ESPoolUtil esPoolUtil = null;

    /**
     *初始化ES客户端连接池
     */
    @PostConstruct
    public void initESPoolUtil() {
        this.esPoolUtil = new ESPoolUtil(elasticSerachInfo.address,
                elasticSerachInfo.port,
                elasticSerachInfo.clustername,
                elasticSerachInfo.clientpoolmaxtotal,
                elasticSerachInfo.clientpoolminEvictableIdle,
                elasticSerachInfo.clientpooltimeBetweenEviction);
    }

    /**
     * 查询全文检索信息关键字代码高亮
     * created on 2018/03/28
     *
     * @param serviceID 服务ID
     * @param keyword   检索关键字
     * @return 检索结果
     * @author guoyanfei
     */
    @RequestMapping(value = "/seachDataHighlight", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "查询全文检索信息关键字代码高亮")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageNO", value = "当前页码", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页条数", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "keyword", value = "检索关键字", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "hightstyle", value = "代码高亮css样式", required = false, dataType = "String", paramType = "query")
    })
    public Object seachDataHighlight(String serviceID, String keyword, String pageNO,
                                     String pageSize, String hightstyle) {
        JsonDataResult jsonResult = new JsonDataResult();
        try {
            if (serviceID == null || serviceID.equals("")) {
                jsonResult.setResult(901);
                jsonResult.setMessage("serviceID没有传入值或拼写错误!");
                return jsonResult;
            }
            if (keyword == null || keyword.equals("")) {
                jsonResult.setResult(901);
                jsonResult.setMessage("keyword关键字没有传入值或拼写错误!");
                return jsonResult;
            }
            Integer pageindex = 1;
            Integer pagerow = 20;
            if (pageNO != null && !pageNO.equals("")) {
                pageindex = Integer.valueOf(pageNO);
            }
            if (pageSize != null && !pageSize.equals("")) {
                pagerow = Integer.valueOf(pageSize);
            }
            if (StringUtils.isEmpty(hightstyle)) {
                hightstyle = "color:red;font-weight:bold;font-size:16px;";
            }
            IKkeyword(keyword, serviceID);
            CfgExtsearch cfgExtsearch = redisCacheComponent.selectCfgExtSearchRedisCache(serviceID);
            if (cfgExtsearch != null) {
                ESPageResponse<Map<String, Object>> mapdata =
                        getSerarchData(cfgExtsearch, pageindex, pagerow, keyword, hightstyle);
                jsonResult.setResult(0);
                jsonResult.setData(mapdata);
                jsonResult.setMessage("查询成功!");
            }
        } catch (Exception e) {
            logger.error("查询全文检索信息关键字代码高亮异常", e);
        }
        return jsonResult;
    }

    /**
     * 查询全文检索信息
     * created on 2018/03/28
     *
     * @param serviceID 服务ID
     * @param keyword   检索关键字
     * @return 检索结果
     * @author guoyanfei
     */
    @RequestMapping(value = "/seachData", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "查询全文检索信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageNO", value = "当前页码", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页条数", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "keyword", value = "检索关键字", required = true, dataType = "String", paramType = "query")
    })
    public Object seachData(String serviceID, String keyword, String pageNO, String pageSize) {
        JsonDataResult jsonResult = new JsonDataResult();
        try {
            if (serviceID == null || serviceID.equals("")) {
                jsonResult.setResult(901);
                jsonResult.setMessage("serviceID没有传入值或拼写错误!");
                return jsonResult;
            }
            if (keyword == null || keyword.equals("")) {
                jsonResult.setResult(901);
                jsonResult.setMessage("keyword关键字没有传入值或拼写错误!");
                return jsonResult;
            }
            Integer pageindex = 1;
            Integer pagerow = 20;
            if (pageNO != null && !pageNO.equals("")) {
                pageindex = Integer.valueOf(pageNO);
            }
            if (pageSize != null && !pageSize.equals("")) {
                pagerow = Integer.valueOf(pageSize);
            }
            IKkeyword(keyword, serviceID);
            CfgExtsearch cfgExtsearch = redisCacheComponent.selectCfgExtSearchRedisCache(serviceID);
            if (cfgExtsearch != null) {
                ESPageResponse<Map<String, Object>> mapdata =
                        getSerarchData(cfgExtsearch, pageindex, pagerow, keyword);
                jsonResult.setResult(0);
                jsonResult.setData(mapdata);
                jsonResult.setMessage("查询成功!");
            }
        } catch (Exception e) {
            logger.error("查询全文检索信息", e);
        }
        return jsonResult;
    }

    /**
     * 查询项目文档全文检索信息
     * created on 2018/04/23
     *
     * @param serviceID 服务ID
     * @param keyword   检索关键字
     * @param pageNO    当前页
     * @param pageSize  页大小
     * @return 检索结果
     * @author guoyanfei
     */
    @RequestMapping(value = "/seachDocData", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "查询项目文档全文检索信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageNO", value = "当前页码", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页条数", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "keyword", value = "检索关键字", required = true, dataType = "String", paramType = "query"),
            //增加检索文件名
            @ApiImplicitParam(name = "filenames", value = "检索文件名", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "hightstyle", value = "代码高亮css样式", required = false, dataType = "String", paramType = "query")
    })
    public Object seachDocData(String serviceID, String filenames, String keyword, String pageNO, String pageSize, String hightstyle, Boolean includesContext) {
        //增加filename
        ArrayList<String> filename = new ArrayList<>();
        if (!StringUtils.isEmpty(filenames)) {
            String[] filesname = filenames.split("\\|");
            for (String fn : filesname) {
                if (!StringUtils.isEmpty(fn)) {
                    filename.add(fn);
                }
            }
        }
        JsonDataResult jsonResult = new JsonDataResult();
        try {
            if (serviceID == null || serviceID.equals("")) {
                jsonResult.setResult(901);
                jsonResult.setMessage("serviceID没有传入值或拼写错误!");
                return jsonResult;
            }
            if (keyword == null || keyword.equals("")) {
                jsonResult.setResult(901);
                jsonResult.setMessage("keyword关键字没有传入值或拼写错误!");
                return jsonResult;
            }
            Integer pageindex = 1;
            Integer pagerow = 20;
            if (pageNO != null && !pageNO.equals("")) {
                pageindex = Integer.valueOf(pageNO);
            }
            if (pageSize != null && !pageSize.equals("")) {
                pagerow = Integer.valueOf(pageSize);
            }
            SysDocument sysDocument = sysDocumentService.selectInfoByserviceId(serviceID);
            if (sysDocument == null) {
                jsonResult.setResult(901);
                jsonResult.setMessage("请配置项目非结构化文档信息");
                return jsonResult;
            }
            if (StringUtils.isEmpty(hightstyle)) {
                hightstyle = "color:red;font-weight:bold;font-size:16px;";
            }

            IKkeyword(keyword, serviceID);

            //是否包括文档内容
            Boolean IsFileContext = true;
            IsFileContext = includesContext;
            //需显示字段集合
            String[] showfields = null;
            if (IsFileContext) {
                showfields = new String[]{"filename", "modifytime", "docSourceDescribe", "filecontext", "filesize", "docpath", "docSource"};
            } else {
                showfields = new String[]{"filename", "modifytime", "docSourceDescribe", "filesize", "docpath", "docSource"};
            }

            ESPageResponse<Map<String, Object>> esPageResponse = new ESPageResponse<>();
            ESClient esClient = this.esPoolUtil.getClient();
            esPageResponse = esClient.searchDocumentToField(sysDocument.getGuid(), sysDocument.getIndextype(),
                    pageindex, pagerow, "filecontext", filename, keyword, hightstyle, showfields, IsFileContext);
            jsonResult.setResult(0);
            jsonResult.setData(esPageResponse);
            jsonResult.setMessage("查询成功!");
            esPoolUtil.returnClient(esClient);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return jsonResult;
    }


    /**
     * 查询检索热词
     * created by guoyanfei on 2018/05/02
     *
     * @return 热词list集合
     */
    @RequestMapping(value = "/seachHotword", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "查询检索热词")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query")
    })
    public Object seachHotword(String serviceID) {
        SysPrjservice sysPrjservice = sysDocumentService.getSysPrjserviceByid(serviceID);
        String key = hotkey + sysPrjservice.getPcode();
        Set<String> hotwords = redisTemplate.opsForZSet().reverseRange(key, 0, 4);
        List<String> hotwordlist = new ArrayList<>(hotwords);
        return hotwordlist;
    }

    /**
     * 通过关键字查询elasticsearch索引库数据
     * created on 2018/03/28
     *
     * @param cfgExtsearch 全文检索服务基本信息
     * @param pageNO       当前页
     * @param pageSize     页大小
     * @param keyword      关键字
     * @return 检索数据集合
     * @author guoyanfei
     */
    private ESPageResponse<Map<String, Object>> getSerarchData(CfgExtsearch cfgExtsearch,
                                                               Integer pageNO, Integer pageSize, String keyword) {
        ESPageResponse<Map<String, Object>> esPageResponse = new ESPageResponse<>();
        List<FullTextSearchVo> fullTextSearchVos = redisCacheDataBase.selectFullTextSearchRedisCache(cfgExtsearch.getGuid());
        if (fullTextSearchVos != null && fullTextSearchVos.size() > 0) {
            String fieldtxt = "";
            for (FullTextSearchVo fulltext : fullTextSearchVos) {
                if (fulltext.getFieldidcode() != null && !fulltext.getFieldidcode().equals("")) {
                    if (fieldtxt.equals("")) {
                        fieldtxt = fulltext.getFieldidcode();
                    } else {
                        fieldtxt += "," + fulltext.getFieldidcode();
                    }
                }
            }

            ESClient esClient = new ESClient(elasticSerachInfo.address, elasticSerachInfo.port, elasticSerachInfo.clustername);
            esPageResponse = esClient.searchDocument(cfgExtsearch.getGuid(),
                    cfgExtsearch.getIndextype(), pageNO, pageSize, fieldtxt, keyword);
        }

        return esPageResponse;
    }

    /**
     * 通过关键字查询elasticsearch索引库数据关键字代码高亮
     * created on 2018/03/28
     *
     * @param cfgExtsearch 全文检索服务基本信息
     * @param pageNO       当前页
     * @param pageSize     页大小
     * @param keyword      关键字
     * @param hightstyle   关键字代码高亮样式
     * @return 检索数据集合
     * @author guoyanfei
     */
    private ESPageResponse<Map<String, Object>> getSerarchData(CfgExtsearch cfgExtsearch,
                                                               Integer pageNO, Integer pageSize, String keyword, String hightstyle) {
        ESPageResponse<Map<String, Object>> esPageResponse = new ESPageResponse<>();
        List<FullTextSearchVo> fullTextSearchVos = redisCacheDataBase.selectFullTextSearchRedisCache(cfgExtsearch.getGuid());
        if (fullTextSearchVos != null && fullTextSearchVos.size() > 0) {
            String fieldtxt = "";
            for (FullTextSearchVo fulltext : fullTextSearchVos) {
                if (fulltext.getFieldidcode() != null && !fulltext.getFieldidcode().equals("")) {
                    if (fieldtxt.equals("")) {
                        fieldtxt = fulltext.getFieldidcode();
                    } else {
                        fieldtxt += "," + fulltext.getFieldidcode();
                    }
                }
            }

            ESClient esClient = new ESClient(elasticSerachInfo.address, elasticSerachInfo.port, elasticSerachInfo.clustername);
            esPageResponse = esClient.searchDocumentHighlight(cfgExtsearch.getGuid(),
                    cfgExtsearch.getIndextype(), pageNO, pageSize, fieldtxt, keyword, hightstyle);
        }

        return esPageResponse;
    }

    /**
     * 使用IK分词关键字，并把热词保存到Radis缓存
     * created by guoyanfei on 2018/05/02
     *
     * @param keyword   关键词
     * @param serviceId 服务ID
     */
    private void IKkeyword(String keyword, String serviceId) {
        List<String> list = new ArrayList<>();
        StringReader sr = new StringReader(keyword);
        IKSegmenter ik = new IKSegmenter(sr, true);
        Lexeme lex;
        try {
            while ((lex = ik.next()) != null) {
                if (lex.getLexemeText().length() > 1) {
                    list.add(lex.getLexemeText());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        keywordRedis(list, serviceId);
    }

    /**
     * 把检索热词保存到redis缓存中
     * created by guoyanfei no 2018/05/02
     *
     * @param list      热词集合
     * @param serviceId 服务ID
     */
    private void keywordRedis(List<String> list, String serviceId) {
        SysPrjservice sysPrjservice = sysDocumentService.getSysPrjserviceByid(serviceId);
        String key = hotkey + sysPrjservice.getPcode();
        if (list != null && list.size() > 0) {
            for (String str : list) {
                if (redisTemplate.opsForZSet().rank(key, str) == null) {
                    redisTemplate.opsForZSet().add(key, str, 1);
                } else {
                    redisTemplate.opsForZSet().incrementScore(key, str, 1);
                }
            }
        }
    }

}
